#include "../include/TcpConnection.h"
#include "../include/EventLoop.h"
#include "../include/Logger.h"
#include "../include/Packet.h"
#include "../include/TLV.h"
#include <string.h>
#include <sstream>
#include <pthread.h>

using std::ostringstream;

namespace myNameSpace {
TcpConnection::TcpConnection(int connectFd, EventLoop *pEventLoop): _connectSock(connectFd), _sockIO(connectFd), _localAddr(getLocalAddr()), _peerAddr(getPeerAddr()), _pEventLoop(pEventLoop) {}

void TcpConnection::send(const string &msg) {
    if (msg.size() > 0) {
        _sockIO.sendn(msg.c_str(), msg.size());
    }
    moqi::LOG_INFO("Thread %u: Response %u bytes.", pthread_self(), msg.size());
}

void TcpConnection::sendTLV(const TLV &tlv) {
    /* if (tlv._length > 0) { */
        _sockIO.sendn((const char *)&tlv, sizeof(int) + sizeof(int) + tlv._length);
    /* } */
    moqi::LOG_INFO("Thread %u: Response %u bytes.", pthread_self(), sizeof(int) + sizeof(int) + tlv._length);
}

string TcpConnection::receive() {
    if (!isClosed()) {
        char buf[65536] = {0};
        int ret = _sockIO.readLine(buf, sizeof(buf)); // 读一行数据，读到的字符数包括末尾的'\n'（但读到buf中后已被替换为'\0'）
        moqi::LOG_INFO("Thread %u: Recv %d bytes: %s.", pthread_self(), ret - 1, buf);
        return string(buf, ret - 1); // 第二个参数强制要求用buf的前ret-1个字节构建字符串，防止buf[0.ret)中有'\0'导致构建不完全
    }
    return string();
}

int TcpConnection::readPacket(Packet &packet) {
    if (!isClosed()) {
        int ret = _sockIO.readPacket(packet);
        moqi::LOG_INFO("Thread %u: Read packet, %d bytes, type: %d, length: %d, msg: %s.", pthread_self(), ret, packet._type, packet._length, packet._msg.c_str());
        return ret;
    }
    return 0;
}

string TcpConnection::getConnectionInfo() const {
    ostringstream oss;
    oss << "TcpConnection[" << _localAddr.getIp() << ":" << _localAddr.getPort() << "-->" << _peerAddr.getIp() << ":" << _peerAddr.getPort() << "]";
    return oss.str();
}

bool TcpConnection::isClosed() const {
    char buf[10] = {0};
    int ret = _sockIO.recvPeek(buf, sizeof(buf));
    return ret == 0;
}

void TcpConnection::shutdown() {
    _connectSock.shutdownWrite();
}

void TcpConnection::setNewConnectionCallback(TcpConnectionCallback &cb) {
    _onNewConnection = cb;
}

void TcpConnection::setMessageCallback(TcpConnectionCallback &cb) {
    _onMessage = cb;
}

void TcpConnection::setCloseCallback(TcpConnectionCallback &cb) {
    _onClose = cb;
}

void TcpConnection::handleNewConnectionCallback() {
    if (_onNewConnection) {
        _onNewConnection(shared_from_this()); // 使用shared_from_this创建一个托管this指针的shared_ptr
    }
}

void TcpConnection::handleMessageCallback() {
    if (_onMessage) {
        _onMessage(shared_from_this());
    }
}

void TcpConnection::handleCloseCallback() {
    if (_onClose) {
        _onClose(shared_from_this());
    }
}

void TcpConnection::notifyEventLoopToSendResponse(const string &response) {
    if (_pEventLoop) {
        _pEventLoop->addSendTaskAndNotify(std::bind(&TcpConnection::send, this, response));
    }
}

void TcpConnection::sendInLoop(const TLV &response) {
    if (_pEventLoop) {
        _pEventLoop->addSendTaskAndNotify(std::bind(&TcpConnection::sendTLV, this, response));
    }
}

InetAddress TcpConnection::getLocalAddr() const {
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    memset(&addr, 0, len);
    int ret = getsockname(_connectSock.getFd(), (struct sockaddr *)&addr, &len);
    if (ret == -1) {
        perror("getsockname");
    }
    return InetAddress(addr);
}

InetAddress TcpConnection::getPeerAddr() const {
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    memset(&addr, 0, len);
    int ret = getpeername(_connectSock.getFd(), (struct sockaddr *)&addr, &len);
    if (ret == -1) {
        perror("getpeername");
    }
    return InetAddress(addr);
}
} // end of namespace myNameSpace
